# -*- coding: utf-8 -*-
""" A class to choose files interactively.

    :Author:
      - 20091202-20100321 Nicola Creati
      - 20111202-20120214 Roberto Vidmar

    :Revision:  $Revision: 52 $
                $Date: 2012-11-12 09:07:15 +0000 (Mon, 12 Nov 2012) $

    :Copyright: 2011-2012
                Nicola Creati <ncreati@inogs.it>
                Roberto Vidmar <rvidmar@inogs.it>

    :License: MIT/X11 License (see :download:`license.txt
                               <../../license.txt>`)
"""

import os

from qtCompat import Signal, Qt, QtCore, QtGui, getOpenFileName, getSaveFileName
QCA = QtCore.QCoreApplication

from fileBrowser import FileBrowser

#==============================================================================
class TinyButton(QtGui.QPushButton):
  """ A QPushButton with a size fitted to the button label
  """
  def __init__(self, label, parent):
    """ Create a new TinyButton instance.

      :param label: label to put on the tiny button
      :type label: string
      :param parent: parent widget
      :type parent: QtGui widget
      :raises:
    """
    super(TinyButton, self).__init__(label, parent)

    textWidth = self.fontMetrics().boundingRect(self.text()).width()
    self.setMaximumWidth(textWidth + 12)
    self.setFocusPolicy(Qt.NoFocus)

#==============================================================================
class FileValidator(QtGui.QValidator):
  def __init__(self, parent=None):
    """ Create a new FileValidator instance.

      :param parent: parent widget
      :type parent: QtGui widget
      :raises:
    """
    super(FileValidator, self).__init__(parent)

  def validate(self, path, l):
    """ Reimplementation of the validate method.

      :param path: file path to check
      :type path: string or unicode
      :param l: lenght
      :type l: int
      :returns: result, path, l
      :rtype: QtGui.QValidator.Acceptable or QtGui.QValidator.Intermediate,
              string or unicode, int
      :raises:
    """
    if isinstance(path, tuple):
      path, selectedFilter = path
    palette = self.parent().palette()

    if QtCore.QFileInfo(path).isFile():
      palette.setColor(QtGui.QPalette.Base, QtGui.QColor('white'))
      self.parent().setPalette(palette)
      result = QtGui.QValidator.Acceptable
    else:
      palette.setColor(QtGui.QPalette.Base, QtGui.QColor('SALMON'))
      self.parent().setPalette(palette)
      result = QtGui.QValidator.Intermediate
    return result, path, l

#==============================================================================
class FilePicker(QtGui.QWidget):
  """ A File picker class
  """
  pathChanged = Signal(str)
  InputMode = 0
  OutputMode = 1

  def __init__(self, parent=None, pn=None, filt=u'*', extension='=',
    mode=InputMode, home='', viewer=None, toolTip=None):
    """ Create a new FileValidator instance.

      :param parent: parent widget
      :type parent: QtGui widget
      :param pn: optional pathname
      :type pn: valid pathname
      :param filt: file extension filter
      :type filt: string
      :param extension: extension to use for the viewer (default is full
                        pathname). *Valid only if viewer is defined.*
      :type extension: string
      :param mode: either :class:`InputMode` or :class`OutputMode`
      :type mode: int
      :param home: open picker in this directory
      :type home: string or unicode
      :param viewer: an optional file viewer class whose init accepts parent
                     and path keyword arguments
      :type viewer: class
      :param toolTip: An optional toolTip
      :type toolTip: string
      :raises:
    """
    # Attributes
    self._filter = filt
    self._directory = home
    self._viewer = None
    self._ext = extension
    self._path = None
    if viewer == 'default':
      self.viewerClass = FileBrowser
    else:
      self.viewerClass = viewer

    # Create the widget
    super(FilePicker, self).__init__(parent)
    # populate it
    if pn and os.path.isfile(pn):
      self._editor = QtGui.QLineEdit(pn, self)
    else:
      self._editor = QtGui.QLineEdit(self)

    self._browse = TinyButton(u"\N{DOWNWARDS DOUBLE ARROW}", self)

    # Layout        
    layout = QtGui.QHBoxLayout(self)
    layout.addWidget(self._editor)
    layout.addWidget(self._browse)
    layout.setContentsMargins(0, 0, 0, 0)
    layout.setSpacing(0)

    # Signals
    self._editor.editingFinished.connect(self.fileSelected)
    self._browse.clicked.connect(self._selectFile)

    if self.viewerClass:
      self._viewBtn = TinyButton(u"\N{LOWER RIGHT DROP-SHADOWED WHITE SQUARE}",
        self)
      layout.addWidget(self._viewBtn)
      self._viewBtn.clicked.connect(self._showFile)
    else:
      self._viewBtn = None

    self.setMode(mode, toolTip)

  def setMode(self, mode, toolTip='', caption=None):
    """ Set Widget mode: either :class:`InputMode` or :class:`OutputMode`
        A caption of None defaults to `mode`

      :param mode: either :class:`InputMode` or :class:`OutputMode`
      :type mode: int
      :param toolTip: An optional toolTip
      :type toolTip: string
      :param caption: optional caption
      :type caption: string or unicode
      :raises:
    """
    if mode == self.InputMode:
      self._dialog = getOpenFileName
      self._caption = QCA.translate("filePicker", "Open file")
      self._browse.setToolTip(QCA.translate("filePicker",
        "Click to select the input file"))
      if toolTip is None:
        self._editor.setToolTip(QCA.translate("filePicker",
          "Enter here the name of the file to convert"))
      else:
        self._editor.setToolTip(toolTip)
      self._editor.setValidator(FileValidator(self._editor))
    else:
      self._dialog = getSaveFileName
      self._caption = QCA.translate("filePicker", "Save to")
      if toolTip is None:
        self._browse.setToolTip(QCA.translate("filePicker",
          "Click to select the output file"))
      else:
        self._editor.setToolTip(toolTip)
      self._editor.setToolTip(QCA.translate("filePicker",
        "Enter here the name of the output file"))
      self._editor.setValidator(None)
    self._mode = mode
    if caption is not None:
      self._caption = caption

    # Enable drops
    self.setAcceptDrops(True)

  def dragEnterEvent(self, evt):
    """ Reimplemented to tell the drag and drop system that we can only
        handle plain text

      :param evt: event
      :type evt: QtCore.QEvent
      :raises:
    """
    if evt.mimeData().hasUrls():
      evt.accept()
    else:
      evt.ignore()

  def dropEvent(self, evt):
    """ Reimplemented to copy the first dropped url into the editor

      :param evt: event
      :type evt: QtCore.QEvent
      :raises:
    """
    if evt.mimeData().hasUrls():
      evt.setDropAction(QtCore.Qt.CopyAction)
      evt.accept()

      url = evt.mimeData().urls()[0]
      pn = str(url.toLocalFile())
      self._editor.setText(pn)
      self.fileSelected()
    else:
      evt.ignore()

  def text(self):
    """ Return text content

      :returns: text content
      :rtype: unicode
      :raises:
    """
    return unicode(self._editor.text())

  def _selectFile(self):
    """ Select file using an appropriate dialog
    """
    options = QtGui.QFileDialog.DontUseNativeDialog
    if not self._editor.text():
      absPath = self._directory
    else:
      absPath = os.path.abspath(self._editor.text())
    fileName = self._dialog(self, self._caption, absPath,
      filter=self._filter, options=options)

    if fileName:
      self._editor.setText(fileName)
      self.fileSelected()

  def fileSelected(self):
    """ File has been selected: emit the Signal
    """
    if self._path != self._editor.text():
      self._path = self._editor.text()
      self.pathChanged.emit(self._path)

  def _showFile(self):
    """ Show ascii file in a viewer
    """
    if self._editor.text():
      if self._viewer:
        self._viewer.close()
      if self._ext == '=':
        path = str(self._editor.text())
      else:
        path = (os.path.splitext(str(self._editor.text()))[0] + self._ext)
      self._viewer = self.viewerClass(parent=self._viewBtn, path=path)
      self._viewer.resize(640, 480)
      self._viewer.setWindowTitle('%s' % path)
      self._viewer.show()

#==============================================================================
if __name__ == "__main__":
  import sys
  import signal
  signal.signal(signal.SIGINT, signal.SIG_DFL)

  app = QtGui.QApplication(sys.argv)
  f = FilePicker(pn=__file__, home=QtCore.QDir.homePath(),
    filt='Python modules (*.py)', viewer='default')
  #f = FilePicker(home=QtCore.QDir.homePath())
  f.show()
  sys.exit(app.exec_())
